#include<bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i(a);i<=(b);++i)
#define req(i,a,b) for(int i(a);i>=(b);--i)
#define sort stable_sort
using namespace std;
char buf[1<<23],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
template<typename TP> inline TP read(TP &num)
{
	TP x=0;
	int f=0;
	char ch=getchar();
	while(ch<48||ch>57) f|=ch=='-',ch=getchar();
	while(48<=ch&&ch<=57) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return num=f?-x:x;
}
template<typename ...Args> inline void read(Args &...args)
{
	(read(args),...);
}
template<typename TP> inline void write(TP x)
{
	(x<0)?(putchar('-'),x=-x):0;
	(x>9)?(write(x/10),0):0;
	putchar((x%10)^48);
}
template<typename TP> inline void writeln(TP x)
{
	write<TP>(x);
	puts("");
}
constexpr int mod=6661;
int fac[mod],ifac[mod],inv[mod],pre[mod][mod],pw2[mod];
inline int qpow(int x,int y)
{
	int res=1;
	while(y)
	{
		if(y&1) res=res*x%mod;
		x=x*x%mod,y>>=1;
	}
	return res;
}
inline int C(int n,int m)
{
	if(m<0||n<m) return 0;
	return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
inline void init()
{
	fac[0]=pw2[0]=1;
	rep(i,1,mod-1) fac[i]=fac[i-1]*i%mod,pw2[i]=(pw2[i-1]<<1)%mod;
	ifac[mod-1]=qpow(fac[mod-1],mod-2);
	req(i,mod-2,0) ifac[i]=ifac[i+1]*(i+1)%mod;
	rep(i,1,mod-1) inv[i]=ifac[i]*fac[i-1]%mod;
	rep(b,0,mod-1)
	{
		int s=0;
		rep(r,0,mod-1)
		{
			s+=C(b,r); (s>=mod)&&(s-=mod);
			pre[b][r]=s;
		}
	}
}
inline int lucas(int k,int x)
{
	int res=1;
	while(k||x)
	{
		int a=k%mod,b=x%mod;
		if(a<b) return 0;
		res=res*C(a,b)%mod;
		k/=mod,x/=mod;
	}
	return res;
}
int presum(int k,int m)
{
	if(m<0) return 0;
	int a=k/mod,c=m/mod,sum=0;
	if(a>=mod||c>=mod) sum=presum(a,c-1);
	else sum=c<=0?0:pre[a][c-1];
	sum=sum*pw2[k%mod]%mod;
	sum+=lucas(a,c)*pre[k%mod][m%mod];
	return sum%mod;
}
struct odt
{
	int l,r; mutable pair<int,int> val;
	odt(int l1,int r1=-1,pair<int,int> val1={0,0}):l(l1),r(r1),val(val1){}
	bool operator<(const odt &rhs)const{return l<rhs.l;}
};
set<odt> T;
inline auto split(int x)
{
	auto it=T.lower_bound(odt(x));
	if(it->l==x&&it!=T.end()) return it;
	int l2=(--it)->l,r2=it->r; pair<int,int> val2=it->val;
	T.erase(it),T.insert(odt(l2,x-1,val2));
	return T.insert(odt(x,r2,val2)).first;
}
inline void assign(int l,int r,pair<int,int> v)
{
	auto itr=split(r+1),itl=split(l);
	T.erase(itl,itr),T.insert(odt(l,r,v));
}
inline int calc(int x,int l,int r)
{
	int ans=presum(x,r)-presum(x,l-1); ((ans<0)&&(ans+=mod));
	return ans;
}
inline void recover(int x)
{
	auto it=T.lower_bound(odt(x));
	int l2=it->l,r2=it->r; pair<int,int> val2=it->val;
	if(it==T.begin()) return;
	int l3=(--it)->l,r3=it->r; pair<int,int> val3=it->val;
	if(val2!=val3) return;
	int newl=min(l2,l3),newr=max(r2,r3);
	auto nxt=next(it);
	T.erase(it),T.erase(nxt),T.insert(odt(newl,newr,val2));
}
inline int query(int l,int r)
{
	auto itr=split(r+1),itl=split(l);
	int ans=0,tot=0;
	for(auto it=itl;it!=itr;++it) ans=(ans+calc(it->val.first,it->l-it->val.second+1,it->r-it->val.second+1))%mod,++tot;
	recover(l),recover(r+1);
	return ans;
}
int n,q,k;
signed main()
{
	freopen("izumi.in","r",stdin);
	freopen("izumi.out","w",stdout);
	read(n,q,k); T.insert(odt(1,n,{k,1}));
	init();
	while(q--)
	{
		int opt,l,r,x;
		read(opt,l,r);
		if(opt==1) read(x),assign(l,r,{x,l});
		else writeln(query(l,r));
	}
	return 0;
}
